# -*- coding: UTF-8 -*-
import commands
import json
import logging
import os
import socket
import thread
import threading
import time
import xml.etree.ElementTree as ET

import conf
import log_helper
import lte_controller
import power_helper
import send_initinfo
import tcp_server
from utils import ip_utils
from utils import ssh_utils
from utils import xml_utils

logger = logging.getLogger('report')

is_ready = False
asked = False
working = False


def btsinfo_req(req_data):
    device_info = ip_utils.get_device_info()
    device_type = device_info.split('-')[1]
    bandinfo = int(device_type[1:])
    xml_info = read_xml_info()
    band = power_helper.get_band()
    power = power_helper.get_power()
    return {'cmd_type': 'BtsInfo_resp',
            'device_id': req_data.get('device_id', ''),
            'oper_id': req_data.get('oper_id', ''),
            'params': {'type': 'WCDMA',
                       'bandinfo': bandinfo,
                       'band': band,
                       'earfcn': xml_info['earfcn'],
                       'lac': xml_info['lac'],
                       'psc': xml_info['psc'],
                       'cellid': xml_info['cellid'],
                       'plmnid': xml_info['plmnid'],
                       'power': power
                       }
            }


def device_status(req_data):
    status = send_initinfo.get_device_status()
    powerstatus = power_helper.get_all_power_status()
    return {'cmd_type': 'DeviceStatus_resp',
            'device_id': req_data.get('device_id', ''),
            'params': {'result': 'WCDMA', 'status': status, 'power_status': powerstatus,
                       'description': 'query success'}}


def set_wcdma(req_data):
    PrimaryDNS = req_data.get('params', {}).get('PrimaryDNS')
    SecondaryDNS = req_data.get('params', {}).get('SecondaryDNS')
    # 上网数据出口ip
    PacketGwIP = req_data.get('params', {}).get('PacketGwIP')
    try:
        config_xml = "/root/ucn_app/ucn_conf.xml"
        tree = ET.parse(config_xml)
        root = tree.getroot()
        settings = root.findall('settings')
        for setting in settings:
            if setting.attrib.get('name') == 'PS_CFG':
                all_set = setting.findall('set')
                for st in all_set:
                    if st.attrib.get('key') == 'DNS_PRIMARY':
                        st.set('value', PrimaryDNS)
                    if st.attrib.get('key') == 'DNS_SECOND':
                        st.set('value', SecondaryDNS)
        tree.write(config_xml, encoding="utf-8", xml_declaration=True)
        update_packetgwip(PacketGwIP)
        result = 'success'
        description = 'set wcdma success'
    except Exception as e:
        result = 'failed'
        description = 'set error.%s' + str(e)
    return {'cmd_type': 'SetWCDMA _resp',
            'device_id': req_data.get('device_id', ''),
            'oper_id': req_data.get('oper_id', ''),
            'params': {'result': result,
                       'description': description}}


def update_packetgwip(PacketGwIP):
    if not PacketGwIP:
        return
    file_path = '/root/ucn_app/ggsnCfg'
    cmd = 'sed -i "s/GateWay_IP=.*/GateWay_IP=' + str(PacketGwIP) + '/" ' + file_path
    logger.info(cmd)
    os.system(cmd)


def set_mode(req_data):
    mode = req_data.get('params', {}).get('mode')
    config_file = "/root/ucn_app/whiteList.config"
    with open(config_file, 'r') as f:
        config_data = f.read()
    config_lines = config_data.split('\n')
    current_mode = 'white'
    for line in config_lines:
        if line.startswith('supportWhiteList'):
            mode_flag = line.split('=')[1]
            if mode_flag == 'true':
                current_mode = 'white'
            else:
                current_mode = 'black'
    if current_mode != mode:
        if mode == 'white':
            new_line = 'supportWhiteList=true'
        else:
            new_line = 'supportWhiteList=false'
        with open(config_file, 'w') as f:
            f.write(new_line)
    commands.getstatusoutput('/root/ucn_app/ucn_cli MSC reload_acl')
    result = 'success'
    description = 'setmode ok'
    return {'cmd_type': 'SetMode_resp',
            'device_id': req_data.get('device_id', ''),
            'oper_id': req_data.get('oper_id', ''),
            'params': {'result': result,
                       'description': description}}


def get_device_bts():
    return commands.getstatusoutput('/root/ucn_app/ucn_status.sh |wc -l')


def set_deivce_bts(req_data):
    bts = req_data.get('params', {}).get('setbts')
    result = 'success'
    description = 'setmode ok'
    try:
        if bts == 'start':
            # commands.getstatusoutput('/root/ucn_app/ucn_up.sh')
            # ssh_utils.exec_shell('sh /root/ucn_app/ucn_up2.sh')
            ssh_utils.exec_shell('cd /root/ucn_app && sh ucn_restart.sh ')
            __reboot()
        if bts == 'stop':
            commands.getstatusoutput('/root/ucn_app/ucn_down.sh')
            rst = power_helper.shutdown()
            if rst != '00':
                raise Exception('功放关闭失败%s' % str(rst))
        if bts == 'restart':
            # commands.getstatusoutput('cd /root/ucn_app && sh ucn_restart.sh &')
            ssh_utils.exec_shell('cd /root/ucn_app && sh ucn_restart.sh ')
            __reboot()
    except Exception as e:
        logger.error(log_helper.format_exc_all())
        result = 'fail'
        description = str(e)
    return {'cmd_type': 'SetDevice_resp',
            'device_id': req_data.get('device_id', ''),
            'oper_id': req_data.get('oper_id', ''),
            'params': {'result': result,
                       'description': description}}


def set_list(req_data):
    config_file = "/root/ucn_app/whiteList.config"
    with open(config_file, 'r') as f:
        config_data = f.read().strip()
    config_lines = config_data.split('\n')
    unique_list = [item.split(' ')[0] for item in config_lines]
    operation = req_data.get('params', {}).get('operation')
    voice_phone = req_data.get('params', {}).get('voice_phone', '0')
    # listmode = req_data.get('params', {}).get('listmode')
    listinfo = req_data.get('params', {}).get('listinfo', [])
    if operation == 'add':
        for data in listinfo:
            if data not in unique_list:
                config_lines.append(data + ' ' + voice_phone)
            else:  # 记录已经存在了，更新记录
                for item in config_lines:
                    if item.split(' ')[0] == data:
                        config_lines.remove(item)
                        config_lines.append(data + ' ' + voice_phone)
    if operation == 'del':
        for data in listinfo:
            for item in config_lines:
                if item.split(' ')[0] == data:
                    config_lines.remove(item)
    with open(config_file, 'w') as f:
        f.write('\n'.join(config_lines))
    commands.getstatusoutput('/root/ucn_app/ucn_cli MSC reload_acl')
    if operation == 'del':
        for data in listinfo:
            commands.getstatusoutput('/root/ucn_app/ucn_cli MSC detach %s' % data)
    result = 'success'
    description = 'setlist ok'
    return {'cmd_type': 'SetList_resp',
            'oper_id': req_data.get('oper_id', ''),
            'device_id': req_data.get('device_id', ''),
            'params': {'result': result,
                       'description': description}}


def query_list(req_data):
    list_mode = req_data.get('params', {}).get('listmode')
    config_file = "/root/ucn_app/whiteList.config"
    with open(config_file, 'r') as f:
        config_data = f.read()
    config_lines = config_data.splitlines()
    config_data_new = []
    current_mode = ''
    for line in config_lines:
        if line.startswith('supportWhiteList'):
            mode = line.split('=')[1]
            if mode == 'true':
                current_mode = 'white'
            else:
                current_mode = 'black'
            continue
        config_data_new.append(line)
    if list_mode is None:
        list_mode = current_mode
    if current_mode != list_mode:
        config_data_new = []
    return {'cmd_type': 'QueryList_resp',
            'params': {'listmode': list_mode,
                       'listinfo': config_data_new}}


def set_bts(req_data):
    result = 'success'
    description = 'set ok'
    PLMNid = req_data.get('params', {}).get('PLMNid', '')
    earfcn = req_data.get('params', {}).get('earfcn', '')
    # power = req_data.get('params', {}).get('Power', 1)
    lac = req_data.get('params', {}).get('lac', '')
    psc = req_data.get('params', {}).get('psc', '')
    cellid = req_data.get('params', {}).get('cellid', '')
    distance = req_data.get('params', {}).get('distance', 0)
    try:
        device_info = ip_utils.get_device_info()
        device_type = device_info.split('-')[1]
        bandinfo = int(device_type[1:])
        earfcn_int = int(earfcn)
        if bandinfo == '1':
            if earfcn_int < 10550 or earfcn_int > 10850:
                raise Exception('earfcn should betwen 10550 and 10850')
        if bandinfo == '2':
            if earfcn_int < 9650 or earfcn_int > 9950:
                raise Exception('earfcn should betwen 9650 and 9950')
        if bandinfo == '5':
            if earfcn_int < 4345 or earfcn_int > 4470:
                raise Exception('earfcn should betwen 4345 and 4470')
        if len(PLMNid) not in (5, 6):
            raise Exception('PLMNid value err')
        # is_success = power_helper.set_power_value(power)
        # if not is_success:
        #     raise Exception('set power timeout')
        __set_bts(PLMNid, earfcn, lac, psc, cellid)
        __set_distance(distance)
    except Exception as e:
        logger.error(log_helper.format_exc_all())
        result = 'failt'
        description = 'set err.%s' % str(e)
    return {'cmd_type': 'SetBts_resp',
            'device_id': req_data.get('device_id', ''),
            'oper_id': req_data.get('oper_id', ''),
            'params': {'result': result,
                       'description': description}}


def __set_distance(distance):
    if distance <= 0:
        return
    # current_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
    # config_xml_path = os.path.join(current_dir, "doc/run3g.sh")
    config_xml_path = '/root/run3g.sh'
    cmd = 'sed -i "s/export ANTENNA_TIMING=[0-9]*/export ANTENNA_TIMING=' + str(distance) + '/" ' + config_xml_path
    logger.info(cmd)
    os.system(cmd)
    __scp_file(config_xml_path, '/root/wcdma/3g/run3g.sh')


def __set_bts(plmnid, earfcn, lac, psc, cellid):
    config_xml_path = '/root/svsCellCfg.xml'
    tree = ET.parse(config_xml_path)
    root = tree.getroot()
    utms = root.findall('UMTS')[0]
    # set plmnid
    cn = utms.findall('CN')[0]
    if plmnid:
        plmnid_ele = cn.findall('PLMNID')[0]
        plmnid_ele.text = plmnid
    # lac
    lac_ele = cn.findall('LACInUse')[0]
    lac_ele.text = str(hex(int(lac)))
    # cellid
    ran = utms.findall('RAN')[0]
    cellid_ele = ran.findall('CellID')[0]
    cellid_ele.text = cellid
    # set earfcn
    rf = ran.findall('RF')[0]
    uarfcn = rf.findall('UARFCNDLInUse')[0]
    uarfcn.text = earfcn
    # set psc
    psc_ele = rf.findall('PrimaryScramblingCodeInUse')[0]
    psc_ele.text = psc
    tree.write(config_xml_path, encoding="utf-8", xml_declaration=True)
    __scp_file(config_xml_path, '/root/wcdma/fap/svsCellCfg.xml')
    # __reboot()
    # set lac
    ucn_xml_path = '/root/ucn_app/ucn_conf.xml'
    tree = xml_utils.read_xml(ucn_xml_path)
    root = tree.getroot()
    root.find('settings[@name="General"]/set[@key="MCC"]').attrib['value'] = plmnid[0:3]
    root.find('settings[@name="General"]/set[@key="MNC"]').attrib['value'] = plmnid[3:]
    root.find('settings[@name="General"]/set[@key="LAC"]').attrib['value'] = lac
    tree.write(ucn_xml_path, encoding="utf-8", xml_declaration=True)


def set_power(req_data):
    result = 'success'
    description = 'set ok'
    power = req_data.get('params', {}).get('power', 1)
    is_success = power_helper.set_power_value(power)
    if not is_success:
        result = 'failt'
        description = 'set power timeout'
    return {'cmd_type': 'SetPower_resp',
            'device_id': req_data.get('device_id', ''),
            'oper_id': req_data.get('oper_id', ''),
            'params': {'result': result,
                       'description': description}}


def read_xml_info():
    config_xml_path = '/root/svsCellCfg.xml'
    tree = xml_utils.read_xml(config_xml_path)
    root = tree.getroot()
    psc = root.find('UMTS/RAN/RF/PrimaryScramblingCodeInUse').text.strip()
    cellid = root.find('UMTS/RAN/CellID').text.strip()
    plmnid = root.find('UMTS/CN/PLMNID').text.strip()
    earfcn = root.find('UMTS/RAN/RF/UARFCNDLInUse').text.strip()
    ucn_xml_path = '/root/ucn_app/ucn_conf.xml'
    tree = xml_utils.read_xml(ucn_xml_path)
    root = tree.getroot()
    lac = root.find('settings[@name="General"]/set[@key="LAC"]').attrib['value']
    result = dict()
    result['lac'] = lac
    result['psc'] = psc
    result['cellid'] = cellid
    result['earfcn'] = earfcn
    result['plmnid'] = plmnid
    return result


def __scp_file(src, target):
    connect_param = {
        'host': conf.REMOTE_HOST,
        'port': 22,
        'username': 'root',
        'pwd': conf.REMOTE_PWD
    }
    ssh_client = ssh_utils.SSHConnection(connect_param)
    ssh_client.connect()
    ssh_client.upload(src, target)
    del ssh_client


def __reboot():
    connect_param = {
        'host': conf.REMOTE_HOST,
        'port': 22,
        'username': 'root',
        'pwd': conf.REMOTE_PWD
    }
    ssh_client = ssh_utils.SSHConnection(connect_param)
    ssh_client.connect()
    ssh_client.run_cmd("reboot")
    del ssh_client


def shutdown():
    rst = power_helper.shutdown()
    if rst != '00':
        raise Exception('功放关机失败%s' % str(rst))
    t = threading.Timer(1, __local_shutdown)
    t.start()


def __local_shutdown():
    logger.info('开始关机')
    os.system('poweroff')
    logger.info('关机完成')


def handle_request(request_josn):
    global is_ready, asked
    cmd_type = request_josn.get('cmd_type')
    result = {}
    if cmd_type == 'InitInfo_rep':
        is_ready = True
        new_port = request_josn.get('params').get('port')
        conf.udp_port = new_port
        return ''
    if cmd_type == 'DeviceHeart_resp':
        asked = True
        return ''
    # 1
    if cmd_type == 'BtsInfo_req':
        result = btsinfo_req(request_josn)
    # 2
    if cmd_type == 'DeviceStatus_req':
        result = device_status(request_josn)
    # 3
    if cmd_type == 'SetWCDMA_req':
        result = set_wcdma(request_josn)
    # 4
    if cmd_type == 'SetMode_req':
        result = set_mode(request_josn)
    # 5
    if cmd_type == 'SetDevice_req':
        result = set_deivce_bts(request_josn)
    # 6
    if cmd_type == 'SetList_req':
        result = set_list(request_josn)
    # 7
    if cmd_type == 'QueryList_req':
        result = query_list(request_josn)
    # 8
    if cmd_type == 'SetBts_req':
        result = set_bts(request_josn)
    # 9 支持发送多个号码
    if cmd_type == 'SMSRev':
        params = request_josn['params']
        sms_type = str(params.get('type', '1'))
        if sms_type == '1':
            tcp_server.recive_sms_info(request_josn)
        else:
            tcp_server.receive_sms_media_info(request_josn)
        return ''
    if cmd_type == 'CallRev':
        tcp_server.recive_call_info(request_josn)
        return ''
    # 10
    if cmd_type == 'SetPower_req':
        result = set_power(request_josn)
    # 11
    if cmd_type == 'AuthQuad_resp':
        tcp_server.rec_auth_info(request_josn)
        return ''
    # 12 下载语音文件
    if cmd_type == 'Download_req':
        result = lte_controller.download_tone(request_josn)
    # CallRev
    logger.info('response json :' + json.dumps(result))
    if len(result) == 0:
        return ''
    return json.dumps(result)


def unicode_convert(input_data):
    if isinstance(input_data, dict):
        return {unicode_convert(key): unicode_convert(value) for key, value in input_data.iteritems()}
    elif isinstance(input_data, list):
        return [unicode_convert(element) for element in input_data]
    elif isinstance(input_data, unicode):
        return input_data.encode('utf-8')
    else:
        return input_data


def start_server():
    global is_ready, working
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind(('0.0.0.0', conf.web_port))
    thread.start_new_thread(send_heart, ())
    thread.start_new_thread(start_tcp_server, ())
    while True:
        data, addr = s.recvfrom(1024)
        logger.info('recive data:' + data)
        requset_json = json.loads(data)
        try:
            working = True
            # requset_json = unicode_convert(requset_json)
            result = handle_request(requset_json)
            # s.sendto(result, addr)
            if len(result) > 0:
                send_initinfo.post(result, port=conf.udp_port)
        except Exception as e:
            logger.error('deal data error:' + log_helper.format_exc_all())
            logger.error('err msg :' + str(e))
        finally:
            working = False


def send_heart():
    my_logger = logging.getLogger('heart')
    global is_ready, asked, working
    while True:
        my_logger.info('is_ready=' + str(is_ready))
        if not is_ready:
            send_initinfo.send_request_info()
            time.sleep(10)
        else:
            my_logger.info('send_mormal_heart-----new port' + str(conf.udp_port))
            asked = False
            send_initinfo.send_mormal_heart()
            total_time = 0
            while not asked and not working:
                if total_time > 3:
                    my_logger.info('heart timeout')
                    is_ready = False
                    break
                time.sleep(10)
                total_time += 1
            else:
                time.sleep(10)


def start_tcp_server():
    while True:
        try:
            tcp_server.start_server()
        except Exception as e:
            logger.error('start_server error:' + str(e))
        time.sleep(2)
